﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using System.Reflection;
using System.Threading;
using UtfprLibrary.Windows.Forms.ComponentModel.Security;
using UtfprLibrary.ComponentModel.Security;
using UtfprLibrary.Windows.Forms.ComponentModel;
using UtfprLibrary.Windows.Helpers;

namespace UtfprLibrary.Windows.Forms {
    /// <summary>
    /// The base FormMain of UtfprLibrary, encapsulates the core security behavior in the main entry for the application.
    /// </summary>
    public partial class UtfprFormMainBase : UtfprFormBase {
        public UtfprFormMainBase() {
            createSplashScreenThread();
            InitializeComponent();

            //if (!IsResizable) {
            //    this.MaximumSize = new Size(
            //        Screen.PrimaryScreen.Bounds.Width + 16,
            //        Screen.PrimaryScreen.Bounds.Height - 30);
            //}
        }

        #region Properties

        private bool IsResizable {
            get { return MaximizeBox; }
        }

        private UtfprToolStripBase _toolStripTools;
        [Browsable(false)]
        public UtfprToolStripBase ToolStripTools {
            get {
                if (_toolStripTools == null) {
                    FieldInfo field = null;
                    var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                    var fieldName = UtfprWindowsFormsConsts.UtfprFormMain_ToolStripTools_FieldName;
                    var frmCrud = this.GetType();

                    field = frmCrud.GetField(fieldName, flags);

                    while (field == null) {
                        //limita a verificação na hierarquia até no máximo Form
                        if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                            //recebe o tipo base
                            frmCrud = frmCrud.BaseType;
                        } else {
                            break;
                        }

                        field = frmCrud.GetField(fieldName, flags);
                    }

                    if (field != null) {
                        _toolStripTools = field.GetValue(this) as UtfprToolStripBase;
                    }
                }

                return _toolStripTools;
            }
        }
                
        private UtfprToolStripBase _toolStripUser;
        [Browsable(false)]
        public UtfprToolStripBase ToolStripUser {
            get {
                if (_toolStripUser == null) {
                    FieldInfo field = null;
                    var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                    var fieldName = UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_FieldName;
                    var frmCrud = this.GetType();

                    field = frmCrud.GetField(fieldName, flags);

                    while (field == null) {
                        //limita a verificação na hierarquia até no máximo Form
                        if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                            //recebe o tipo base
                            frmCrud = frmCrud.BaseType;
                        } else {
                            break;
                        }

                        field = frmCrud.GetField(fieldName, flags);
                    }

                    if (field != null) {
                        _toolStripUser = field.GetValue(this) as UtfprToolStripBase;
                    }
                }

                return _toolStripUser;
            }
        }

        private UtfprStatusStripBase _statusStrip;
        [Browsable(false)]
        public UtfprStatusStripBase StatusStrip {
            get {
                if (_statusStrip == null) {
                    FieldInfo field = null;
                    var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                    var fieldName = UtfprWindowsFormsConsts.UtfprFormMain_StatusStrip_FieldName;
                    var frmCrud = this.GetType();

                    field = frmCrud.GetField(fieldName, flags);

                    while (field == null) {
                        //limita a verificação na hierarquia até no máximo Form
                        if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                            //recebe o tipo base
                            frmCrud = frmCrud.BaseType;
                        } else {
                            break;
                        }

                        field = frmCrud.GetField(fieldName, flags);
                    }

                    if (field != null) {
                        _statusStrip = field.GetValue(this) as UtfprStatusStripBase;
                    }
                }

                return _statusStrip;
            }
        }

        private UtfprMenuStripBase _menuStrip;
        [Browsable(false)]
        public UtfprMenuStripBase MenuStrip {
            get {
                if (_menuStrip == null) {
                    FieldInfo field = null;
                    var flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
                    var fieldName = UtfprWindowsFormsConsts.UtfprFormMain_MenuStrip_FieldName;
                    var frmCrud = this.GetType();

                    field = frmCrud.GetField(fieldName, flags);

                    while (field == null) {
                        //limita a verificação na hierarquia até no máximo Form
                        if (frmCrud.BaseType.FullName != typeof(Form).FullName) {
                            //recebe o tipo base
                            frmCrud = frmCrud.BaseType;
                        } else {
                            break;
                        }

                        field = frmCrud.GetField(fieldName, flags);
                    }

                    if (field != null) {
                        _menuStrip = field.GetValue(this) as UtfprMenuStripBase;
                    }
                }

                return _menuStrip;
            }
        }

        #endregion

        #region Override

        ////http://www.syncfusion.com/FAQ/windowsforms/faq_c95c.aspx#q1091q
        ////32.16 How do I prevent a user from moving a form at run time?
        //protected override void WndProc(ref Message m) {
        //    const int WM_NCLBUTTONDOWN = 161;
        //    const int HTCAPTION = 2;

        //    if (!IsResizable) {
        //        if ((m.Msg == WM_NCLBUTTONDOWN) && (m.WParam.ToInt32() == HTCAPTION)) {
        //            return;
        //        }
        //    }

        //    base.WndProc(ref m);
        //}

        #endregion

        #region Event Handlers

        private void UtfprFormMainBase_Load(object sender, EventArgs e) {
            if (!UtfprControlBase.IsInDesignMode) {
                var lblStatus = StatusStrip.Items[UtfprWindowsFormsConsts.UtfprFormMain_StatusStrip_LabelStatus_FieldName];
                var cbxUser = ToolStripUser.Items[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_FieldName] as ToolStripDropDownButton;
                var miLogin = cbxUser.DropDownItems[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_MenuItemLogin_FieldName];
                var miLogout = cbxUser.DropDownItems[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_MenuItemLogout_FieldName];
                
                if (UtfprSecurity.Instance.IsUserConected) {
                    lblStatus.Text = UtfprSecurity.Instance.User.Name;
                    cbxUser.Image = miLogin.Image;
                    miLogin.Visible = false;
                    miLogout.Visible = true;
                    applyUserPermissions();
                } else {
                    lblStatus.Text = "";
                    cbxUser.Image = miLogout.Image;
                    miLogin.Visible = true;
                    miLogout.Visible = false;
                    restrictAllPermissions();
                }
                
                miLogin.Click += new EventHandler(loginToolStripMenuItem_Click);
                miLogout.Click += new EventHandler(logoutToolStripMenuItem_Click);
            }
        }
         
        private void loginToolStripMenuItem_Click(object sender, EventArgs e) {
            UtfprSecurity.Instance.ShowFormLoginDefault();
            if (UtfprSecurity.Instance.IsUserConected) {
                StatusStrip.Items[UtfprWindowsFormsConsts.UtfprFormMain_StatusStrip_LabelStatus_FieldName].Text = UtfprSecurity.Instance.User.Name;
                ToolStripUser.Items[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_FieldName].Image = (ToolStripUser.Items[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_FieldName] as ToolStripDropDownButton).DropDownItems[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_MenuItemLogin_FieldName].Image;
                (ToolStripUser.Items[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_FieldName] as ToolStripDropDownButton).DropDownItems[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_MenuItemLogin_FieldName].Visible = false;
                (ToolStripUser.Items[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_FieldName] as ToolStripDropDownButton).DropDownItems[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_MenuItemLogout_FieldName].Visible = true;
                applyUserPermissions();
            }
        }

        private void logoutToolStripMenuItem_Click(object sender, EventArgs e) {
            UtfprSecurity.Instance.DisconnectCurrentUser();
            StatusStrip.Items[UtfprWindowsFormsConsts.UtfprFormMain_StatusStrip_LabelStatus_FieldName].Text = "";
            ToolStripUser.Items[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_FieldName].Image = (ToolStripUser.Items[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_FieldName] as ToolStripDropDownButton).DropDownItems[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_MenuItemLogout_FieldName].Image;
            (ToolStripUser.Items[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_FieldName] as ToolStripDropDownButton).DropDownItems[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_MenuItemLogin_FieldName].Visible = true;
            (ToolStripUser.Items[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_FieldName] as ToolStripDropDownButton).DropDownItems[UtfprWindowsFormsConsts.UtfprFormMain_ToolStripUser_ButtonSecurity_MenuItemLogout_FieldName].Visible = false;
            restrictAllPermissions();
        }

        private void UtfprFormMainBase_FormClosed(object sender, FormClosedEventArgs e) {
            Application.Exit();
        }

        #endregion

        /// <summary>
        /// Create the splash screen thread if it's enabled (IsSplashEnabled == true) and login is disabled (IsLoginEnabled == false)
        /// </summary>
        private void createSplashScreenThread() {
            if (!UtfprControlBase.IsInDesignMode) {
                if (UtfprApplication.Instance.IsSplashEnabled && !UtfprApplication.Instance.IsLoginEnabled) {
                    Thread splashthread = new Thread(new ThreadStart(UtfprSplashBaseHelper.ShowSplashScreen));
                    splashthread.IsBackground = true;
                    splashthread.Start();
                }
            }
        }

        private bool isOperationPermited(int operationKey) {
            foreach (var restriction in UtfprSecurity.Instance.User.Restrictions.ToList()) {
                foreach (var function in restriction.FunctionsAndOperations.Keys.ToList()) {
                    foreach (var operation in restriction.FunctionsAndOperations[function].ToList()) {
                        if (operationKey == operation.Key) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        private bool isFunctionPermited(int functionKey) {
            foreach (var restriction in UtfprSecurity.Instance.User.Restrictions.ToList()) {
                foreach (var function in restriction.FunctionsAndOperations.Keys.ToList()) {
                    if (functionKey == function.Key) {
                        return true;
                    }
                }
            }
            return false;
        }

        private void teste(UtfprToolStripMenuItemBase item) {
            if (item.UtfprControlBase.IsSecureRestriction) {
                bool isVisible = false;
                if (item.FunctionOrOperationRestriction != null) {
                    if (item.UtfprControlBase.IsFunctionRestriction) {
                        isVisible = isFunctionPermited((item.FunctionOrOperationRestriction as IUtfprKeyName).Key);
                    } else {
                        isVisible = isOperationPermited((item.FunctionOrOperationRestriction as IUtfprKeyName).Key);
                    }
                }
                item.UtfprControlBase.SetVisibleRestriction(isVisible);
            }
            
            var subItemsFunction = item.DropDownItems.OfType<UtfprToolStripMenuItemBase>().ToList();
            foreach (var subItem in subItemsFunction) {
                teste(subItem);
            }
        }

        /// <summary>
        /// Based os user permissions, Enable/Disable all controls marked with property IsSecure=True
        /// </summary>
        private void applyUserPermissions() {
            if (UtfprSecurity.Instance.IsUserConected) {
                #region button
    
                foreach (var item in ToolStripTools.Items.OfType<IUtfprRestrictionService>().ToList()) {
                    if (item.IsSecureRestriction) {
                        bool isVisible = false;
                        if (item.FunctionOrOperationRestriction != null) {
                            if (item.IsFunctionRestriction) {
                                isVisible = isFunctionPermited((item.FunctionOrOperationRestriction as IUtfprKeyName).Key);
                            } else {
                                isVisible = isOperationPermited((item.FunctionOrOperationRestriction as IUtfprKeyName).Key);
                            }
                        } item.SetVisibleRestriction(isVisible);
                    }
                }

                #endregion

                #region MenuItem

                var functionMenuItems = MenuStrip.Items.OfType<UtfprToolStripMenuItemBase>().ToList();
                foreach (var item in functionMenuItems) {
                    teste(item);
                }

                #endregion
            }
        }

        /// <summary>
        /// Disable all controls marked with property IsSecure = true;
        /// </summary>
        private void restrictAllPermissions() {
            //#region Button
            //var functionItems = ToolStripTools.Items.OfType<UtfprToolStripButton>().ToList();
            //foreach (var item in functionItems) {
            //    if (item.IsSecure) {
            //        item.Visible = false;
            //    }
            //}

            //#endregion

            //#region MenuItem

            //#region function

            //var functionMenuItems = MenuStrip.Items.OfType<UtfprToolStripMenuItem>().ToList();
            //foreach (var item in functionMenuItems) {
            //    if (item.IsSecure) {
            //        item.Visible = false;
            //    }

            //    var subItemsFunction = item.DropDownItems.OfType<UtfprToolStripMenuItem>().ToList();
            //    foreach (var subItem in subItemsFunction) {
            //        if (subItem.IsSecure) {
            //            subItem.Visible = false;
            //        }
            //    }

            //}

            //#endregion

            //#endregion
        }
    }
}
